package com.ebs.md.api.abs;

/**
 * Perforce Revision:
 *  $File: //depot/MarketData/commons-md-api/MAIN/src/main/java/com/ebs/md/api/abs/BasicDetailedBookEntry.java $
 *  $Revision: #7 $  $Change: 115128 $  $DateTime: 2012/09/23 15:21:06 $  $Author: Aviad.Yosef $
 */

import java.util.Calendar;
import java.util.concurrent.atomic.AtomicLong;

import com.ebs.md.api.BookSide;
import com.ebs.md.api.IDetailedBookEntry;
import com.ebs.md.api.IIdentifiedOrder;
import com.ebs.md.api.OrderOperation;
import com.ebs.md.api.Rate;


public class BasicDetailedBookEntry 
implements       IDetailedBookEntry
{
	// gened via Eclipse
	private static final long serialVersionUID = -8264353315169248944L;

	protected BookSide   side;
	protected Rate       rate;

	protected String     quoteId;
	protected Calendar   quoteTime;
	
	protected String     dealCode; // bank/node code. value for example: BNYL
	protected String     traderId;
	
	protected AtomicLong amount;
	protected Long       totalAmount; // total amount
	protected Long       displayAmount; // display amount

	protected String     region;
	
	/**
	 * Iceberg Constructor
	 * which contains total and display amounts
	 */
	public BasicDetailedBookEntry(BookSide side, Rate rate, long amount, String quoteId
			, Calendar quoteTime, String dealCode, String traderId
			, long totalAmount, long displayAmount, String region
			) {
		super();
		this.side  = side;
		this.rate  = rate;
		
		this.amount = new AtomicLong(amount);
		
		this.quoteId = quoteId;
		
		this.quoteTime = quoteTime;
		this.dealCode = dealCode;
		this.traderId = traderId;
		
		this.totalAmount   = totalAmount;
		this.displayAmount = displayAmount;
		this.region = region;
	}
	
	/**
	 * Pre Iceberg Constructor
	 */
	public BasicDetailedBookEntry(BookSide side, Rate rate, long amount, String quoteId
			, Calendar quoteTime, String dealCode, String traderId, String region) {
		this(side, rate, amount, quoteId, quoteTime, dealCode, traderId
			, amount, amount, region);
	}
	
	public BasicDetailedBookEntry(BookSide side, Rate rate, long amount, String quoteId
			, Calendar quoteTime, String region) {
		this(side, rate, amount, quoteId, quoteTime
			, null, null, region);
	}

	/**
	 * Pre Iceberg Constructor
	 */
	public BasicDetailedBookEntry(BookSide side, Rate rate, long amount, String quoteId, String region) {
		this(side, rate, amount, quoteId
			, null, null, null, region);
	}
	
	/**
	 * Iceberg Constructor
	 * which contains total and display amounts
	 */
	public BasicDetailedBookEntry(BookSide side, Rate rate, long amount, String quoteId
			, long totalAmount, long displayAmount, String region 
	) {
		this(side, rate, amount, quoteId
				, null, null, null
				, totalAmount, displayAmount, region
		);
	}

	public BasicDetailedBookEntry(IIdentifiedOrder io) {
		this( BookSide.fromOrderSide(io.getSide())
			 , io.getRate()
			 , io.getAmount()
			 , io.getId()
			 , io.getTime()
			 , io.getDealCode()
			 , io.getTraderId()
			 , io.getTotalAmount()
			 , io.getDisplayAmount()
			 , io.getRegion()
			 );
		if ( !OrderOperation.ADD.equals(io.getOperation()) ) {
			throw new IllegalArgumentException("cannot create BookEntry from non 'ADD' order");
		}
	}

	
	public BookSide getSide() {
		return side;
	}
	public Rate getRate() {
		return rate;
	}
	public Long getAmount() {
		return amount.get();
	}
	public Long getTotalAmount() {
		return totalAmount;
	}
	public Long getDisplayAmount() {
		return displayAmount;
	}
	public String getQuoteId() {
		return quoteId;
	}
	public Calendar getQuoteTime() {
		return quoteTime;
	}
	public String getDealCode() {
		return dealCode;
	}
	public String getTraderId() {
		return traderId;
	}

	@Override
	public String getRegion() {
		return region;
	}

	/**
	 * Since iceberg
	 * @return
	 */
	public long getShownAmount() {
		long val = amount.get(); // available
		if ( displayAmount < val ) {
			val = displayAmount;
		}
		if ( val < 0L ) {
			val = 0L;
		}
			
		return val;
	}
	
	public void setExtraDetails(Calendar quoteTime, String dealCode, String traderId) {
		this.quoteTime = quoteTime;
		this.dealCode = dealCode;
		this.traderId = traderId;
	}
	
	public void increaseAmount(long value) {
		amount.addAndGet(value);
	}
	
	public boolean decreaseAmount(long value) {
		long newVal = amount.addAndGet((-1) * value);
		
		return (newVal >= 1);
	}
	
	// generated by Eclipse (on id(quote/order id))
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((quoteId == null) ? 0 : quoteId.hashCode());
		return result;
	}

	// generated by Eclipse (on id(quote/order id))
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		BasicDetailedBookEntry other = (BasicDetailedBookEntry) obj;
		if (quoteId == null) {
			if (other.quoteId != null)
				return false;
		} else if (!quoteId.equals(other.quoteId))
			return false;
		return true;
	}

	public Object clone() throws CloneNotSupportedException {
		BasicDetailedBookEntry be = new BasicDetailedBookEntry(
			  side
			, rate
			, amount.get()
			, quoteId
			, quoteTime
			, dealCode
			, traderId
			, totalAmount
			, displayAmount
			, region
		);
		
		return be;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		
		sb.append(    "quoteId=");
		sb.append(  getQuoteId());
		sb.append(   ",rate=");
		sb.append(  getRate());
		sb.append(",amount=");
		sb.append(  amount.get());
		sb.append(",side=");
		sb.append(  getSide());
		sb.append(",time=");
		Calendar time = getQuoteTime();
		if ( time == null ) {
			sb.append( "null");
		} else {
			sb.append(  time.getTime());
		}
		
		return sb.toString();
	}

}
